<?php
/**
*
* @package shopBB
* @copyright (c) 2008 EXreaction, Lithium Studios
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*
*/

// Stuff required to work with phpBB3
define('IN_PHPBB', true);
$phpbb_root_path = '../';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
include($phpbb_root_path . 'common.' . $phpEx);

$user->session_begin();
$auth->acl($user->data);
$user->setup();

$mode = request_var('mode', '');

if (!$auth->acl_get('a_'))
{
	trigger_error('NOT_AUTHORISED');
}

switch ($mode)
{
	case 'organize_lang' :
		/**
		* to input the file name use HTTP Get vars.
		*  For example, to organize language/en/common.php you type in en/common.  Do not include language/ or .php
		*  You may also send the directory name and it will organize all language files in it and any subdirectories.
		*/
		organize_lang();
	break;

	case 'check_lang' :
		/**
		* Checks language files for unused language keys.
		*/
		check_lang();
	break;

	case 'get_hooks' :
		get_hooks(); // Gets all available hooks and lists them in a file.  For more detail, check the function directly.
	break;

	case 'build_install' : // Build the Installation Schema Files
		build_install();
	break;

	default :
		trigger_error('NO_MODE');
}

/**
* Checks for unused language keys
*/
function check_lang()
{
	global $phpbb_root_path, $phpEx;

	$lang = $used_lang = array();
	// The list of language files we will check for extra keys
	$lang_list = array(
		'mods/info_acp_blogs', 'mods/info_mcp_blogs', 'mods/info_ucp_blogs',
		'mods/blog/acp', 'mods/blog/common', 'mods/blog/mcp', 'mods/blog/misc', 'mods/blog/posting', 'mods/blog/setup', 'mods/blog/ucp', 'mods/blog/view',
	);
	foreach ($lang_list as $file)
	{
		require($phpbb_root_path . 'language/en/' . $file . '.' . $phpEx);
	}

	if ($handle = opendir($phpbb_root_path . 'root'))
	{
	    while (false !== ($file = readdir($handle)))
		{
			if (strpos($file, '.'))
			{
				$file_list[] = $file;
			}
			else
			{
				$dir_list[] = $file;
			}
	    }
	    closedir($handle);
	}

	// Looks a little strange, but it is being done this way so folders get listed first, then files (otherwise it just lists everything alphabetical file)
	if (sizeof($dir_list))
	{
		foreach ($dir_list as $file)
		{
			check_lang_recusive($lang, $used_lang, $file, $phpbb_root_path . 'root', $phpbb_root_path . 'root');
		}
	}

	if (sizeof($file_list))
	{
		foreach ($file_list as $file)
		{
			check_lang_recusive($lang, $used_lang, $file, $phpbb_root_path . 'root', $phpbb_root_path . 'root');
		}
	}

	var_dump(array_diff(array_keys($lang), $used_lang));
	die();
}

/**
* Helper for check_lang()
*/
function check_lang_recusive(&$lang, &$used_lang, $file, $dir, $original_dir)
{
	global $phpEx;

	if ($file == '.' || $file == '..')
	{
		return;
	}

	$file_list = $dir_list = array();

	if (is_dir($dir . '/' . $file))
	{
		if ($handle = opendir($dir . '/' . $file))
		{
		    while (false !== ($file1 = readdir($handle)))
			{
				if (substr($file, -3) == $phpEx)
				{
					$file_list[] = $file1;
				}
				else
				{
					$dir_list[] = $file1;
				}
		    }

		    closedir($handle);
		}

		if (sizeof($dir_list))
		{
			foreach ($dir_list as $file1)
			{
				check_lang_recusive($lang, $used_lang, $file1, $dir . '/' . $file, $original_dir);
			}
		}

		if (sizeof($file_list))
		{
			foreach ($file_list as $file1)
			{
				check_lang_recusive($lang, $used_lang, $file1, $dir . '/' . $file, $original_dir);
			}
		}
	}
	else if (substr($file, -3) == $phpEx || substr($file, -4) == 'html') // Skip non .php/.html files
	{
		//echo $dir . '/' . $file . '<br />';
		$patterns = array(
			'#{L_([A-Z0-9_]+)}#',
			'#lang\[\'([A-Z0-9_]+)\'\]#',
			'#trigger_error\(\'([A-Z0-9_]+)\'#',
			'#confirm_box\(false, \'([A-Z0-9_]+)\'#',
			'#blog_confirm\(\'([A-Z0-9_]+)\'#',
			'#this->page_title =([\s|\t]+)\'([A-Z0-9_]+)\'#',
			'#\'legend([a-zA-Z0-9\'\s\t]+)=> \'([A-Z0-9_]+)\'#',
			'#\'lang\'([\s|\t]+)=> \'([A-Z0-9_]+)\'#',
			'#\'title\'([\s|\t]+)=> \'([A-Z0-9_]+)\'#',
			'#add_log\(\'admin\', \'([A-Z0-9_]+)\'#',
			'#add_log\(\'mod\', \'([A-Z0-9_]+)\'#',
		);
		$handle = @fopen($dir . '/' . $file, "r");
		if ($handle)
		{
			while (!feof($handle))
			{
				$line = fgets($handle, 4096);

				foreach ($patterns as $pattern)
				{
					$matches = array();
					preg_match_all($pattern, $line, $matches);

					if (sizeof($matches[1]))
					{
						foreach ($matches[1] as $key)
						{
							if (trim($key) != '' && !in_array($key, $used_lang))
							{
								// Add the key and explain, confirm to the list
								$used_lang[] = $key;
								$used_lang[] = $key . '_EXPLAIN';
								$used_lang[] = $key . '_CONFIRM';
							}
						}
					}
					if (isset($matches[2]) && sizeof($matches[2]))
					{
						foreach ($matches[2] as $key)
						{
							if (trim($key) != '' && !in_array($key, $used_lang))
							{
								// Add the key and explain, confirm to the list
								$used_lang[] = $key;
								$used_lang[] = $key . '_EXPLAIN';
								$used_lang[] = $key . '_CONFIRM';
							}
						}
					}
				}
			}
			fclose($handle);
		}
	}
}

/**
* Build Install Schemas
*/
function build_install()
{
	global $phpbb_root_path, $phpEx;

	$schema_path = $phpbb_root_path . 'shop/install/schemas/';

	include($phpbb_root_path . 'shop/install/create_schema_files.' . $phpEx);
}

/**
* Gets the available hooks and lists them in a text file.
*
* You must put all of the files from the root/ folder in the mod package into a folder named blog_hooks in the root phpBB3 directory.
* The hook list will be outputted to a file named blog_hooks.txt in the phpBB3 root directory.
*/
function get_hooks()
{
	global $phpbb_root_path;

	$hook_list = '';
	$file_list = $dir_list = array();

	if ($handle = opendir($phpbb_root_path . 'blog_hooks'))
	{
	    while (false !== ($file = readdir($handle)))
		{
			if (strpos($file, '.'))
			{
				$file_list[] = $file;
			}
			else
			{
				$dir_list[] = $file;
			}
	    }
	    closedir($handle);
	}

	// Looks a little strange, but it is being done this way so folders get listed first, then files (otherwise it just lists everything alphabetical file)
	if (sizeof($dir_list))
	{
		foreach ($dir_list as $file)
		{
			get_hooks_recusive($hook_list, $file, $phpbb_root_path . 'blog_hooks', $phpbb_root_path . 'blog_hooks');
		}
	}

	if (sizeof($file_list))
	{
		foreach ($file_list as $file)
		{
			get_hooks_recusive($hook_list, $file, $phpbb_root_path . 'blog_hooks', $phpbb_root_path . 'blog_hooks');
		}
	}

	if ($fp = @fopen($phpbb_root_path . 'blog_hooks.txt', 'wb'))
	{
		@flock($fp, LOCK_EX);
		fwrite($fp, $hook_list);
		@flock($fp, LOCK_UN);
		fclose($fp);
	}
}

/**
* Helper for get_hooks()
*/
function get_hooks_recusive(&$hook_list, $file, $dir, $original_dir)
{
	global $phpEx;

	if ($file == '.' || $file == '..')
	{
		return;
	}

	$file_list = $dir_list = array();

	if (is_dir($dir . '/' . $file))
	{
		if ($handle = opendir($dir . '/' . $file))
		{
		    while (false !== ($file1 = readdir($handle)))
			{
				if (substr($file, -3) == $phpEx)
				{
					$file_list[] = $file1;
				}
				else
				{
					$dir_list[] = $file1;
				}
		    }

		    closedir($handle);
		}

		if (sizeof($dir_list))
		{
			foreach ($dir_list as $file1)
			{
				get_hooks_recusive($hook_list, $file1, $dir . '/' . $file, $original_dir);
			}
		}

		if (sizeof($file_list))
		{
			foreach ($file_list as $file1)
			{
				get_hooks_recusive($hook_list, $file1, $dir . '/' . $file, $original_dir);
			}
		}
	}
	else if (substr($file, -3) == $phpEx && $file != "dev.$phpEx") // Skip non .php files
	{
		$handle = @fopen($dir . '/' . $file, "r");
		if ($handle)
		{
			$tmp_hook_list = '';
			while (!feof($handle))
			{
				$line = fgets($handle, 4096);

				if (strpos($line, 'blog_plugins::plugin_do') !== false)
				{
					$start_pos = strpos($line, "('") + 2;
					$tmp_hook_list .= "\t" . substr($line, $start_pos, strpos($line, "'", $start_pos) - $start_pos) . "\n";
				}
			}
			fclose($handle);

			if ($tmp_hook_list != '')
			{
				$hook_list .= substr($dir, strpos($dir, $original_dir) + strlen($original_dir)) . '/' . $file . "\n";
				$hook_list .= $tmp_hook_list;
				$hook_list .= "\n";
			}
		}
	}

}

/**
* For finding the max string length for the organize_lang function
*/
function find_max_length($lang, &$max_length, $start = 0)
{
	$start_length = $start * 4;

	foreach($lang as $name => $value)
	{
		if (is_array($value))
		{
			find_max_length($value, $max_length, ($start + 1));
		}

		if ((utf8_strlen($name) + $start_length) > $max_length)
		{
			$max_length = (utf8_strlen($name) + $start_length);
		}
	}
}

/**
* For outputting the lines for the organize_lang function
*/
function lang_lines($lang, $max_length, &$output, $start = 0)
{
	$last_letter = '';
	$total_tabs = ceil(($max_length + 3) / 4) - $start;

	if ($start != 0)
	{
		//ksort($lang);
	}

	$last_name = '';
	foreach($lang as $name => $value)
	{
		if ($name == $last_name)
		{
			echo 'Lang Duplicate: ' . $name . '<br />';
		}
		$last_name = $name;

		// make sure to add slashes to single quotes!
		$name = addcslashes($name, "'");

		// add an extra end line if the next word starts with a different letter then the last
		if (substr($name, 0, 1) != $last_letter && $start == 0)
		{
			$output .= "\n";
			$last_letter = substr($name, 0, 1);
		}

		// add the beggining tabs
		for ($i=0; $i <= $start; $i++)
		{
			$output .= "\t";
		}

		// add the beginning of the lang section and add slashes to single quotes for the name
		$output .= "'" . $name . "'";

		// figure out the number of tabs we need to add to the middle, then add them
		$tabs = ($total_tabs - ceil((utf8_strlen($name) + 3) / 4));

		for($i=0; $i <= $tabs; $i++)
		{
			$output .= "\t";
		}

		if (is_array($value))
		{
			$output .= "=> array(\n";
			lang_lines($value, $max_length, $output, ($start + 1));

			for ($i=0; $i <= $start; $i++)
			{
				$output .= "\t";
			}
			$output .= "),\n\n";
		}
		else
		{
			// add =>, then slashes to single quotes and add to the output
			$output .= "=> '" . addcslashes($value, "'") . "',\n";
		}
	}
}

/**
* Organize the language file by the lang keys, then re-output the data to the file
*
* The Filename is inputted by sending it via a HTTP Get variable
*/
function organize_lang($file = false, $skip_errors = false)
{
	global $phpbb_root_path, $phpEx;

	$file = ($file === false) ? request_var('file', 'en/mods/') : $file;

	if (substr($file, -1) == '/')
	{
		$file = substr($file, 0, -1);
	}

	// make sure they have a file name
	if ($file == '')
	{
		if ($skip_errors)
		{
			return;
		}

		trigger_error('No File Specified.');
	}

	// make sure they are not trying to get out of the language directory, otherwise this would be a security risk. ;)
	if (strpos($file, '.'))
	{
		trigger_error('You are not allowed out of the language/ directory.');
	}

	// If the user submitted a directory, do every language file in that directory
	if (is_dir($phpbb_root_path . 'language/' . $file))
	{
		if ($handle = opendir($phpbb_root_path . 'language/' . $file))
		{
		    while (false !== ($file1 = readdir($handle)))
			{
				if ($file1 == '.' || $file1 == '..' || $file1 == '.svn')
				{
					continue;
				}

				if (strpos($file1, ".$phpEx"))
				{
					organize_lang($file . '/' . substr($file1, 0, strpos($file1, ".$phpEx")), true);
				}
				else if (is_dir($phpbb_root_path . 'language/' . $file . '/' . $file1))
				{
					organize_lang($file . '/' . $file1);
				}
		    }
		    closedir($handle);
		}

		// if we went to a subdirectory, return
		if ($file != request_var('file', '') && $file . '/' != request_var('file', ''))
		{
			return;
		}

		trigger_error('Done organizing all of the language files in language/' . $file . '.');
	}

	// include the file
	@include($phpbb_root_path . 'language/' . $file . '.' . $phpEx);

	// make sure it is a valid language file
	if (!isset($lang) || !is_array($lang))
	{
		if ($skip_errors)
		{
			return;
		}

		trigger_error('Bad Language File. language/' . $file);
	}

	// setup the $output var
	$output = '';

	// lets get the header of the file...
	$handle = @fopen($phpbb_root_path . 'language/' . $file . '.' . $phpEx, "r");
	if ($handle)
	{
		$stopped = false;

		while (!feof($handle))
		{
			$line = fgets($handle, 4096);

			// if the line is $lang = array_merge($lang, array( break out of the while loop
			if ($line == '$lang = array_merge($lang, array(' . "\n")
			{
				$stopped = true;
				break;
			}

			$output .= $line;
		}
		fclose($handle);

		if (!$stopped)
		{
			if ($skip_errors)
			{
				echo 'Bad line endings in ' . $phpbb_root_path . 'language/' . $file . '.' . $phpEx . '<br />';
				return;
			}

			trigger_error('Please make sure you are using UNIX line endings.');
		}
	}

	// sort the languages by keys
	ksort($lang);

	// get the maximum length of the name string so we can format the page nicely when we output it
	$max_length = 1;

	find_max_length($lang, $max_length);

	// now add $lang = array_merge($lang, array( to the output
	$output .= '$lang = array_merge($lang, array(';

	lang_lines($lang, $max_length, $output);

	// add the end
	$output .= '));

?>';

	// write the contents to the specified file
	file_put_contents($phpbb_root_path . 'language/' . $file . '.' . $phpEx, $output);
}

/**
* Define the basic structure
* The format:
*		array('{TABLE_NAME}' => {TABLE_DATA})
*		{TABLE_DATA}:
*			COLUMNS = array({column_name} = array({column_type}, {default}, {auto_increment}))
*			PRIMARY_KEY = {column_name(s)}
*			KEYS = array({key_name} = array({key_type}, {column_name(s)})),
*
*	Column Types:
*	INT:x		=> SIGNED int(x)
*	BINT		=> BIGINT
*	UINT		=> mediumint(8) UNSIGNED
*	UINT:x		=> int(x) UNSIGNED
*	TINT:x		=> tinyint(x)
*	USINT		=> smallint(4) UNSIGNED (for _order columns)
*	BOOL		=> tinyint(1) UNSIGNED
*	VCHAR		=> varchar(255)
*	CHAR:x		=> char(x)
*	XSTEXT_UNI	=> text for storing 100 characters (topic_title for example)
*	STEXT_UNI	=> text for storing 255 characters (normal input field with a max of 255 single-byte chars) - same as VCHAR_UNI
*	TEXT_UNI	=> text for storing 3000 characters (short text, descriptions, comments, etc.)
*	MTEXT_UNI	=> mediumtext (post text, large text)
*	VCHAR:x		=> varchar(x)
*	TIMESTAMP	=> int(11) UNSIGNED
*	DECIMAL		=> decimal number (5,2)
*	DECIMAL:	=> decimal number (x,2)
*	PDECIMAL	=> precision decimal number (6,3)
*	PDECIMAL:	=> precision decimal number (x,3)
*	VCHAR_UNI	=> varchar(255) BINARY
*	VCHAR_CI	=> varchar_ci for postgresql, others VCHAR
*/
function get_schema_struct()
{
	$schema_data = array();

	$schema_data['phpbb_shop_items'] = array(
		'COLUMNS'		=> array(
			'item_id'				=> array('UINT', NULL, 'auto_increment'),
			'user_id'				=> array('UINT', 0),
			'user_ip'				=> array('VCHAR:40', ''),

			'item_name'				=> array('STEXT_UNI', '', 'true_sort'),
			'item_desc'				=> array('MTEXT_UNI', ''),
			'item_desc_uid'			=> array('VCHAR:8', ''),
			'item_desc_bitfield'	=> array('VCHAR', ''),
			'item_desc_options'		=> array('UINT:11', 7),
			'item_time'				=> array('TIMESTAMP', 0),
			'item_approved'			=> array('BOOL', 1),
			'item_reported'			=> array('BOOL', 0),

			'item_cost'				=> array('DECIMAL:8', 0),

			'item_attachment'		=> array('BOOL', 0),

			'item_inventory'		=> array('INT:4', -1),

			'item_auction'			=> array('BOOL', 0),

			'item_special'			=> array('UINT', 0),

			'item_edit'				=> array('UINT', 0),
			'item_edit_time'		=> array('TIMESTAMP', 0),
			'item_edit_reason'		=> array('STEXT_UNI', ''),

			'item_delete'			=> array('UINT', 0),
			'item_delete_time'		=> array('TIMESTAMP', 0),
			'item_delete_reason'	=> array('STEXT_UNI', ''),

			'item_rating'			=> array('DECIMAL:6', 0),
			'item_rating_cnt'		=> array('UINT', 0),
		),
		'PRIMARY_KEY'	=> 'item_id',
		'KEYS'			=> array(
			'user_id'				=> array('INDEX', 'user_id'),
			'item_name'				=> array('INDEX', 'item_name'),
			'item_approved'			=> array('INDEX', 'item_approved'),
			'item_reported'			=> array('INDEX', 'item_reported'),
			'item_delete'			=> array('INDEX', 'item_delete_time'),
			'item_rating'			=> array('INDEX', 'item_rating'),
		),
	);

	$schema_data['phpbb_shop_auctions'] = array(
		'COLUMNS'		=> array(
			'item_id'				=> array('UINT', 0),
			'user_id'				=> array('UINT', 0),
			'bid'					=> array('DECIMAL:8', 0),
		),
		'PRIMARY_KEY'	=> array('item_id', 'user_id'),
	);

	$schema_data['phpbb_shop_special_items'] = array(
		'COLUMNS'		=> array(
			'special_id'			=> array('UINT', NULL, 'auto_increment'),
			'special_file'			=> array('VCHAR', ''),
			'special_commands'		=> array('MTEXT_UNI', ''),
		),
		'PRIMARY_KEY'	=> 'special_id',
	);

	$schema_data['phpbb_shop_plugins'] = array(
		'COLUMNS'		=> array(
			'plugin_id'				=> array('UINT', NULL, 'auto_increment'),
			'plugin_name'			=> array('STEXT_UNI', '', 'true_sort'),
			'plugin_enabled'		=> array('BOOL', 0),
			'plugin_version'		=> array('XSTEXT_UNI', '', 'true_sort'),
		),
		'PRIMARY_KEY'	=> 'plugin_id',
		'KEYS'			=> array(
			'plugin_name'			=> array('INDEX', 'plugin_name'),
			'plugin_enabled'		=> array('INDEX', 'plugin_enabled'),
		),
	);

	$schema_data['phpbb_shop_purchases'] = array(
		'COLUMNS'		=> array(
			'user_id'				=> array('UINT', 0),
			'item_id'				=> array('UINT', 0),
			'payment_type'			=> array('VCHAR', ''),
			'payment_confirmed'		=> array('BOOL', 0),
		),
		'PRIMARY_KEY'	=> array('user_id', 'item_id'),
	);

	$schema_data['phpbb_shop_categories'] = array(
		'COLUMNS'		=> array(
			'category_id'				=> array('UINT', NULL, 'auto_increment'),
			'parent_id'					=> array('UINT', 0),
			'left_id'					=> array('UINT', 0),
			'right_id'					=> array('UINT', 0),
			'category_name'				=> array('STEXT_UNI', '', 'true_sort'),
			'category_desc'				=> array('MTEXT_UNI', ''),
			'category_desc_uid'			=> array('VCHAR:8', ''),
			'category_desc_bitfield'	=> array('VCHAR', ''),
			'category_desc_options'		=> array('UINT:11', 7),
			'category_rules'			=> array('MTEXT_UNI', ''),
			'category_rules_uid'		=> array('VCHAR:8', ''),
			'category_rules_bitfield'	=> array('VCHAR', ''),
			'category_rules_options'	=> array('UINT:11', 7),
			'item_count'				=> array('UINT', 0),
		),
		'PRIMARY_KEY'	=> 'category_id',
		'KEYS'			=> array(
			'left_right_id'			=> array('INDEX', array('left_id', 'right_id')),
		),
	);

	$schema_data['phpbb_shop_items_in_categories'] = array(
		'COLUMNS'		=> array(
			'category_id'			=> array('UINT', 0),
			'item_id'				=> array('UINT', 0),
		),
		'PRIMARY_KEY'	=> array('category_id', 'item_id'),
	);

	return $schema_data;
}

trigger_error('Done.');
?>